package com.zyj.core.handler.parameterhandler;

import com.zyj.core.sqlsource.BoundSql;
import com.zyj.core.sqlsource.ParameterMapping;
import com.zyj.core.utils.SimpleTypeRegistry;

import java.sql.PreparedStatement;
import java.util.List;
import java.util.Map;

public class DefaultParameterHandler implements ParameterHandler {
    /**
     * 调用preparedStatement对象给sql设置参数值
     *
     * @param preparedStatement 预编译Statement对象
     * @param param             客户端传入的参数名称和参数值，如果是多个参数，则是map类型，如果是单个参数，则是简单类型，其中保存了参数名称和参数值
     *                          Map map = new HashMap();
     *                          map.put("username", "千年老亚瑟");
     *                          map.put("sex", "男");
     * @param boundSql          其中封装了sql与参数映射关系【参数名称及对应的参数类型】
     * @throws Exception
     */
    @Override
    public void setPatameter(PreparedStatement preparedStatement, Object param, BoundSql boundSql) throws Exception {
        /**
         * 根据客户端传入的参数对象来判断参数是简单类型还是map类型
         */
        // 如果参数是简单类型，只有一个参数
        if (SimpleTypeRegistry.isSimpleType(param.getClass())) {
            /**
             * 调用预编译Statement对象给sql设置参数值
             */
            preparedStatement.setObject(1, param);
        } else if (param instanceof Map) {
            // 如果参数是map类型，存在多个参数
            Map map = (Map) param;

            /**
             * 从boundSql取出参数映射
             */
            // 解析sql中的#{}会得到参数列表，并将参数名称和参数类型封装成参数映射存入集合中，再将参数映射集合交给boundSql对象封装持有
            // boundSql中持有解析完成的sql语句以及该sql所对应的参数映射集合
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

            // 循环遍历参数映射集合中的所有参数映射
            for (int i = 0; i < parameterMappings.size(); i++) {
                // 按顺序取出参数映射集合中的所有参数
                ParameterMapping parameterMapping = parameterMappings.get(i);
                // 从参数映射中取出参数名称
                String name = parameterMapping.getName();
                // 根据参数名称从传入的参数map中取出该参数名对应的参数值 比如说 根据 username 从map中取出 "千年老亚瑟"
                Object value = map.get(name);

                /**
                 * 调用预编译Statement对象给sql设置参数值
                 *
                 * 解析sql封装参数映射时是按照参数的前后次序封装并且添加到参数映射集合中的，因此取出的第i个参数映射正好对应sql中的第i个参数
                 */
                // 按顺序给sql语句的各个参数设置参数值
                preparedStatement.setObject(i + 1, value);
            }
        }
    }
}
